#pragma once
#include <cassert>
#include <cstdarg>
#include <memory>
#include <mutex>
#include <source_location>

#include "Level.h"
#include "AsyncWorker.h"
#include "LogFlush.h"
#include "ThreadPool.h"
#include "LogFormatter.h"

namespace mylog
{
    class AsyncLogger
    {
    public:
        using ptr = std::shared_ptr<AsyncLogger>;
        AsyncLogger(const std::string& loggerName, 
                    std::vector<LogFlush::ptr>& flushs, 
                    AsyncType type, 
                    std::string_view pattern, 
                    mylog::LogLevel::value level = mylog::LogLevel::value::DEBUG);
        virtual ~AsyncLogger() = default;
        inline std::string name() const { return logger_name_; }

        void debug(const std::string& msg, std::source_location loc = std::source_location::current());
        void info(const std::string& msg, std::source_location loc = std::source_location::current());
        void warn(const std::string& msg, std::source_location loc = std::source_location::current());
        void error(const std::string& msg, std::source_location loc = std::source_location::current());
        void fatal(const std::string& msg, std::source_location loc = std::source_location::current());

    protected:
        void serialize(LogLevel::value level, const std::string& file, size_t line, const std::string& payload);
        void flush(const char* data, size_t len);
        void realFlush(Buffer& buffer);

    protected:
        std::mutex mtx_;
        std::string logger_name_;
        std::vector<LogFlush::ptr> flushs_;
        mylog::AsyncWorker::ptr asyncworker_;
        std::unique_ptr<ThreadPool> tp_; // 用于处理error和fatal日志的远端备份
        LogFormatter::ptr formatter_;
        LogLevel::value level_;
    };

    class LoggerBuilder
    {
    public:
        using ptr = std::shared_ptr<LoggerBuilder>;
        void buildLoggerName(const std::string& name)
        {
            logger_name_ = name;
        }

        void buildLoggerType(AsyncType type)
        {
            async_type_ = type;
        }

        void buildFormatPattern(std::string_view pattern)
        {
            pattern_ = pattern;
        }

        void buildLogLevel(mylog::LogLevel::value level)
        {
            level_ = level;
        }

        template<typename FlushType, typename... Args>
        void buildLoggerFlush(Args&&... args)
        {
            flushs_.emplace_back(LogFlushFactory::CreateLog<FlushType>(std::forward<Args>(args)...));
        }

        AsyncLogger::ptr build()
        {
            // 断言名字必须非空
            assert(!logger_name_.empty());
            if (flushs_.empty())
                flushs_.emplace_back(std::make_shared<StdoutFlush>());
            return std::make_shared<AsyncLogger>(logger_name_, flushs_, async_type_, pattern_, level_);
        }

    private:
        std::string logger_name_ = "async_logger";
        AsyncType async_type_ = AsyncType::ASYNC_SAFE;
        std::vector<mylog::LogFlush::ptr> flushs_;
        std::string pattern_;
        LogLevel::value level_;
    };
} // namespace log